package com.linksoul.aop;

import com.linksoul.common.Result;
import com.linksoul.domain.MbtiRequestLog;
import com.linksoul.mapper.MbtiRequestLogMapper;
import com.linksoul.utils.RequestIdHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: cc
 * @Date: 2025/05/01/15:37
 **/
@Aspect
@Component
public class RequestLogAspect {

    @Autowired
    private MbtiRequestLogMapper logMapper;

    @Autowired
    private HttpServletRequest request;

    @Around("@annotation(com.linksoul.annotation.LogMBTIRequest)")
    public Object logRequest(ProceedingJoinPoint joinPoint) throws Throwable {
        String requestId = RequestIdHolder.get();
        if (requestId == null) {
            throw new IllegalStateException("请求ID未初始化，请检查拦截器配置");
        }

        // 解析请求信息
        String userAgent = request.getHeader("User-Agent");
        String ip = getClientIP();
        String platform = parsePlatform(userAgent);

        // 创建初始日志记录
        MbtiRequestLog log = new MbtiRequestLog();
        log.setRequestId(requestId);
        log.setStatus("initiated");
        log.setUserAgent(userAgent);
        log.setIpAddress(ip);
        log.setPlatform(platform);
        log.setStartTime(new Date());
        log.setCreatedAt(new Date());
        log.setUpdatedAt(new Date());
        // 创建初始日志记录（新增本地缓存）
        MbtiRequestLog initialLog = createInitialLog(requestId);
        logMapper.insert(initialLog);

        try {
            // 执行目标方法
            Object result = joinPoint.proceed();

            // 处理成功结果
            updateLogSuccess(requestId, result, initialLog.getStartTime());
            return result;

        } catch (Exception e) {
            // 处理失败情况
            updateLogFailure(requestId, e);
            throw e;
        }
    }
    private int extractQuestionCount(Object result) {
        if (result instanceof Result) {
            Result<?> res = (Result<?>) result;
            if (res.getData() instanceof List) {
                return ((List<?>) res.getData()).size();
            }
        }
        return 0;
    }

    private void updateLogSuccess(String requestId, Object result, Date startTime) {
        Date endTime = new Date();
        long duration = endTime.getTime() - startTime.getTime();

        int questionCount = extractQuestionCount(result);

        logMapper.updateStatus(
                requestId,
                "completed",
                endTime,
                (int) duration,
                questionCount,
                null
        );
    }

    private void updateLogFailure(String requestId, Exception e) {
        logMapper.updateStatus(
                requestId,
                "failed",
                new Date(),
                null,
                null,
                e.getMessage()
        );
    }

    private String getClientIP() {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    private String parsePlatform(String userAgent) {
        if (userAgent == null) return "other";
        if (userAgent.contains("Mobi")) return "mobile";
        if (userAgent.contains("Android")) return "android";
        if (userAgent.contains("iPhone")) return "ios";
        if (userAgent.contains("Windows")) return "web";
        if (userAgent.contains("Mac")) return "web";
        return "other";
    }
    private MbtiRequestLog createInitialLog(String requestId) {
        String userAgent = request.getHeader("User-Agent");

        return new MbtiRequestLog()
                .setRequestId(requestId)
                .setStatus("initiated")
                .setUserAgent(userAgent)
                .setIpAddress(getClientIP())
                .setPlatform(parsePlatform(userAgent))
                .setStartTime(new Date())
                .setCreatedAt(new Date())
                .setUpdatedAt(new Date());
    }
}
